import { getLength, getArea } from 'ol/sphere';
import { LineString, Polygon } from 'ol/geom';
import { Overlay } from 'ol';
import { Feature } from 'ol';
import { Map as OlMap } from 'ol';
import { Style, Fill, Stroke, Circle as CircleStyle, Text } from 'ol/style';
import { unByKey } from 'ol/Observable';
import { Draw } from 'ol/interaction';
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import { transform } from 'ol/proj';
import { ElNotification } from 'element-plus';

/**
 * 测量工具类 - 用于计算绘制的线路距离和面积，并显示结果
 */
export class MeasureUtils {
  private map: OlMap;
  private source: VectorSource;
  private layer: VectorLayer<any>;
  private draw: Draw | null = null;
  private measureTooltipElement: HTMLElement | null = null;
  private measureTooltip: Overlay | null = null;
  private helpTooltipElement: HTMLElement | null = null;
  private helpTooltip: Overlay | null = null;
  private sketch: Feature | null = null;
  private listener: any = null;
  private isMeasuring: boolean = false;
  private overlays: Overlay[] = [];
  private mouseMoveListener: any = null; // 存储鼠标移动监听器

  /**
   * 构造函数
   * @param map OpenLayers地图实例
   */
  constructor(map: OlMap) {
    console.log('初始化 MeasureUtils');
    this.map = map;
    
    // 创建矢量图层源和图层
    this.source = new VectorSource();
    this.layer = new VectorLayer({
      source: this.source,
      style: new Style({
        fill: new Fill({
          color: 'rgba(255, 255, 255, 0.2)'
        }),
        stroke: new Stroke({
          color: '#ffcc33',
          width: 2
        }),
        image: new CircleStyle({
          radius: 7,
          fill: new Fill({
            color: '#ffcc33'
          })
        })
      }),
      zIndex: 999 // 确保测量图层在最上层
    });
    
    // 添加图层到地图
    this.map.addLayer(this.layer);
    console.log('测量图层已添加到地图');
  }

  /**
   * 启动距离测量
   * @returns 返回清理函数，用于停止测量
   */
  public startMeasureDistance(): () => void {
    console.log('开始距离测量');
    // 如果已经在测量中，先清除当前测量
    if (this.isMeasuring) {
      this.clearMeasurement();
    } else {
      // 即使不在测量中，也要清除可能存在的提示覆盖物
      this.clearAllTooltips();
    }
    
    this.isMeasuring = true;
    
    try {
      // 创建测量提示
      this.createMeasureTooltip();
      
      // 初始化绘图工具，设置为线型
      this.draw = new Draw({
        source: this.source,
        type: 'LineString',
        style: new Style({
          fill: new Fill({
            color: 'rgba(255, 255, 255, 0.2)'
          }),
          stroke: new Stroke({
            color: '#ffcc33',
            width: 2
          }),
          image: new CircleStyle({
            radius: 5,
            stroke: new Stroke({
              color: 'rgba(0, 0, 0, 0.7)'
            }),
            fill: new Fill({
              color: '#ffcc33'
            })
          })
        })
      });
      
      console.log('添加距离测量交互到地图');
      this.map.addInteraction(this.draw);
      
      // 添加绘图开始事件监听
      this.draw.on('drawstart', this.handleDrawStart.bind(this));
      
      // 添加绘图结束事件监听
      this.draw.on('drawend', this.handleDrawEndDistance.bind(this));
      
    } catch (error) {
      console.error('启动距离测量失败:', error);
      this.clearMeasurement();
      throw error;
    }
    
    // 返回清理函数
    return () => this.clearMeasurement();
  }

  /**
   * 处理绘图开始事件
   */
  private handleDrawStart(evt: any): void {
    try {
      this.sketch = evt.feature;
      
      // 获取线的第一个坐标作为初始提示位置
      const geom = evt.feature.getGeometry();
      let tooltipCoord = geom.getFirstCoordinate();
      
      // 确保移除之前的几何变化监听器
      if (this.listener) {
        unByKey(this.listener);
        this.listener = null;
      }
      
      // 添加几何变化监听，实时更新测量值
      this.listener = this.sketch.getGeometry()?.on('change', (e: any) => {
        const geom = e.target;
        if (geom instanceof LineString) {
          const output = this.formatLength(geom);
          tooltipCoord = geom.getLastCoordinate();
          if (this.measureTooltipElement) {
            this.measureTooltipElement.innerHTML = "距离: " + output;
            this.measureTooltip?.setPosition(tooltipCoord);
          }
        } else if (geom instanceof Polygon) {
          const output = this.formatArea(geom);
          tooltipCoord = geom.getInteriorPoint().getCoordinates();
          if (this.measureTooltipElement) {
            this.measureTooltipElement.innerHTML = "面积: " + output;
            this.measureTooltip?.setPosition(tooltipCoord);
          }
        }
      });
    } catch (error) {
      console.error('处理绘图开始事件失败:', error);
    }
  }

  /**
   * 处理距离测量结束事件
   */
  private handleDrawEndDistance(): void {
    try {
      if (!this.sketch) return;
      
      // 获取最终的几何对象
      const geom = this.sketch.getGeometry() as LineString;
      const length = this.formatLength(geom);
      
      // 先移除临时测量提示
      if (this.measureTooltip) {
        this.map.removeOverlay(this.measureTooltip);
        this.measureTooltip = null;
      }
      if (this.measureTooltipElement && this.measureTooltipElement.parentNode) {
        this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement);
      }
      this.measureTooltipElement = null;
      
      // 创建一个永久性标签显示最终距离
      this.createPermanentLabel(geom.getLastCoordinate(), "距离: " + length);
      
      // 显示通知
      this.showNotification("距离测量", `测量完成: ${length}`);
      
      // 移除几何变化监听器
      if (this.listener) {
        unByKey(this.listener);
        this.listener = null;
      }
      
      // 停止绘图交互
      if (this.draw) {
        // 移除事件监听
        try {
          this.draw.un('drawstart', this.handleDrawStart.bind(this));
          this.draw.un('drawend', this.handleDrawEndDistance.bind(this));
        } catch (e) {
          console.warn('移除绘图事件监听器失败:', e);
        }
        
        this.map.removeInteraction(this.draw);
        this.draw = null;
      }
      
      this.sketch = null;
      
      // 绘图结束后，测量状态设置为false，但不清除图层
      this.isMeasuring = false;
    } catch (error) {
      console.error('处理绘图结束事件失败:', error);
    }
  }

  /**
   * 启动面积测量
   * @returns 返回清理函数，用于停止测量
   */
  public startMeasureArea(): () => void {
    console.log('开始面积测量');
    // 如果已经在测量中，先清除当前测量
    if (this.isMeasuring) {
      this.clearMeasurement();
    } else {
      // 即使不在测量中，也要清除可能存在的提示覆盖物
      this.clearAllTooltips();
    }
    
    this.isMeasuring = true;
    
    try {
      // 创建测量提示
      this.createMeasureTooltip();
      
      // 初始化绘图工具，设置为多边形
      this.draw = new Draw({
        source: this.source,
        type: 'Polygon',
        style: new Style({
          fill: new Fill({
            color: 'rgba(255, 255, 255, 0.2)'
          }),
          stroke: new Stroke({
            color: '#ffcc33',
            width: 2
          }),
          image: new CircleStyle({
            radius: 5,
            stroke: new Stroke({
              color: 'rgba(0, 0, 0, 0.7)'
            }),
            fill: new Fill({
              color: '#ffcc33'
            })
          })
        })
      });
      
      console.log('添加面积测量交互到地图');
      this.map.addInteraction(this.draw);
      
      // 添加绘图开始事件监听
      this.draw.on('drawstart', this.handleDrawStart.bind(this));
      
      // 添加绘图结束事件监听
      this.draw.on('drawend', this.handleDrawEndArea.bind(this));
      
    } catch (error) {
      console.error('启动面积测量失败:', error);
      this.clearMeasurement();
      throw error;
    }
    
    // 返回清理函数
    return () => this.clearMeasurement();
  }

  /**
   * 处理面积测量结束事件
   */
  private handleDrawEndArea(): void {
    console.log('处理面积测量结束事件');
    try {
      if (!this.sketch) return;
      
      // 获取最终的几何对象
      const geom = this.sketch.getGeometry() as Polygon;
      const area = this.formatArea(geom);
      
      // 先移除临时测量提示
      if (this.measureTooltip) {
        this.map.removeOverlay(this.measureTooltip);
        this.measureTooltip = null;
      }
      if (this.measureTooltipElement && this.measureTooltipElement.parentNode) {
        this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement);
      }
      this.measureTooltipElement = null;
      
      // 创建一个永久性标签显示最终面积
      this.createPermanentLabel(geom.getInteriorPoint().getCoordinates(), "面积: " + area);
      
      // 显示通知
      this.showNotification("面积测量", `测量完成: ${area}`);
      
      // 移除几何变化监听器
      if (this.listener) {
        unByKey(this.listener);
        this.listener = null;
      }
      
      // 停止绘图交互
      if (this.draw) {
        // 移除事件监听
        try {
          this.draw.un('drawstart', this.handleDrawStart.bind(this));
          this.draw.un('drawend', this.handleDrawEndArea.bind(this));
        } catch (e) {
          console.warn('移除绘图事件监听器失败:', e);
        }
        
        this.map.removeInteraction(this.draw);
        this.draw = null;
      }
      
      this.sketch = null;
      
      // 绘图结束后，测量状态设置为false，但不清除图层
      this.isMeasuring = false;
    } catch (error) {
      console.error('处理绘图结束事件失败:', error);
    }
  }

  /**
   * 创建并显示永久性标签
   */
  private createPermanentLabel(position: number[], text: string): void {
    const element = document.createElement('div');
    element.className = 'ol-tooltip ol-tooltip-static';
    element.innerHTML = text;
    
    const overlay = new Overlay({
      element: element,
      offset: [0, -15],
      positioning: 'bottom-center',
      stopEvent: false
    });
    
    overlay.setPosition(position);
    this.map.addOverlay(overlay);
    
    // 保存overlay引用以便后续清理
    this.overlays.push(overlay);
  }

  /**
   * 使用Element Plus显示通知
   */
  private showNotification(title: string, message: string): void {
    try {
      ElNotification({
        title: title,
        message: message,
        type: 'success',
        duration: 3000,
        position: 'top-right'
      });
    } catch (error) {
      console.error('显示通知失败:', error);
      // 使用原生alert作为备选
      alert(`${title}: ${message}`);
    }
  }

  /**
   * 清除所有测量（线、面、提示等）
   */
  public clearMeasurement(): void {
    console.log('清除所有测量');
    
    // 移除绘图交互
    if (this.draw) {
      // 先移除事件监听器，避免内存泄漏
      try {
        this.draw.un('drawstart', this.handleDrawStart.bind(this));
        this.draw.un('drawend', this.handleDrawEndDistance.bind(this));
        this.draw.un('drawend', this.handleDrawEndArea.bind(this));
      } catch (error) {
        console.warn('移除绘图事件监听器失败:', error);
      }
      
      this.map.removeInteraction(this.draw);
      this.draw = null;
    }
    
    // 检查并移除所有可能的绘图交互
    const interactions = this.map.getInteractions().getArray();
    for (let i = interactions.length - 1; i >= 0; i--) {
      const interaction = interactions[i];
      if (interaction instanceof Draw) {
        console.log('移除额外的绘图交互');
        this.map.removeInteraction(interaction);
      }
    }
    
    // 移除几何变化监听器
    if (this.listener) {
      unByKey(this.listener);
      this.listener = null;
    }
    
    // 清除所有要素
    this.source.clear();
    
    // 清除所有提示和覆盖物
    this.clearAllTooltips();
    
    // 移除可能存在的鼠标事件监听器
    this.clearMouseListeners();
    
    // 重置状态变量
    this.isMeasuring = false;
    this.sketch = null;
    
    console.log('测量已完全清除');
    
    // 返回地图到适当的状态，避免任何残留的交互状态
    // 重新对地图触发一次moveend事件，确保所有状态都被更新
    this.map.dispatchEvent('moveend');
  }

  /**
   * 清除所有提示覆盖物
   */
  public clearAllTooltips(): void {
    console.log('清除所有提示覆盖物');
    // 移除测量提示
    if (this.measureTooltip) {
      this.map.removeOverlay(this.measureTooltip);
      this.measureTooltip = null;
    }
    
    // 移除帮助提示
    if (this.helpTooltip) {
      this.map.removeOverlay(this.helpTooltip);
      this.helpTooltip = null;
    }
    
    // 从DOM中移除元素
    if (this.measureTooltipElement && this.measureTooltipElement.parentNode) {
      this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement);
    }
    if (this.helpTooltipElement && this.helpTooltipElement.parentNode) {
      this.helpTooltipElement.parentNode.removeChild(this.helpTooltipElement);
    }
    
    this.measureTooltipElement = null;
    this.helpTooltipElement = null;
    
    // 清除鼠标移动监听器
    if (this.mouseMoveListener) {
      this.map.un('pointermove', this.mouseMoveListener);
      this.mouseMoveListener = null;
    }
    
    // 移除所有永久性标签
    this.overlays.forEach(overlay => {
      this.map.removeOverlay(overlay);
    });
    this.overlays = [];
    
    // 确保移除所有可能残留的提示元素
    const overlays = this.map.getOverlays().getArray().slice();
    overlays.forEach(overlay => {
      const element = overlay.getElement();
      if (element && 
         (element.className.includes('ol-tooltip') || 
          element.className.includes('tooltip-measure') || 
          element.className.includes('tooltip-static'))) {
        this.map.removeOverlay(overlay);
      }
    });
    
    // 清除文档中所有可能残留的测量提示DOM元素
    try {
      const tooltips = document.querySelectorAll('.ol-tooltip, .ol-tooltip-measure, .ol-tooltip-static');
      tooltips.forEach(tooltip => {
        if (tooltip.parentNode) {
          tooltip.parentNode.removeChild(tooltip);
        }
      });
    } catch (e) {
      console.warn('清除DOM中的测量提示元素失败:', e);
    }
  }
  
  /**
   * 清除可能遗留的鼠标事件监听器
   */
  private clearMouseListeners(): void {
    try {
      // 由于 OpenLayers 的事件系统限制，清除特定监听器存在困难
      // 我们主要确保清除已知的测量相关监听器
      
      // 清除可能存在的帮助提示相关的鼠标移动监听器
      if (this.map && this.mouseMoveListener) {
        this.map.un('pointermove', this.mouseMoveListener);
        this.mouseMoveListener = null;
      }
      
      // 清除潜在的绘图事件监听器 - 这已经在 clearMeasurement 中处理
      
      console.log('已清除测量相关的鼠标事件监听器');
    } catch (error) {
      console.error('清除鼠标事件监听器时发生错误:', error);
    }
  }

  /**
   * 创建测量提示
   */
  private createMeasureTooltip(): void {
    // 确保移除任何现有的测量提示
    if (this.measureTooltip) {
      this.map.removeOverlay(this.measureTooltip);
      this.measureTooltip = null;
    }
    
    if (this.measureTooltipElement) {
      if (this.measureTooltipElement.parentNode) {
        this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement);
      }
      this.measureTooltipElement = null;
    }
    
    // 创建新的测量提示元素
    this.measureTooltipElement = document.createElement('div');
    this.measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure';
    
    this.measureTooltip = new Overlay({
      element: this.measureTooltipElement,
      offset: [0, -15],
      positioning: 'bottom-center',
      stopEvent: false,
      insertFirst: false
    });
    
    this.map.addOverlay(this.measureTooltip);
  }

  /**
   * 格式化线段长度
   * @param line 线段几何对象
   * @returns 格式化后的长度字符串
   */
  private formatLength(line: LineString): string {
    // 获取坐标
    const coordinates = line.getCoordinates();
    
    // 确保至少有两个点
    if (coordinates.length < 2) {
      return '0 m';
    }
    
    // 将线的坐标转换为地理坐标系（EPSG:4326），如果不是的话
    let transformedCoordinates = coordinates;
    const projection = this.map.getView().getProjection();
    
    if (projection.getCode() !== 'EPSG:4326') {
      transformedCoordinates = coordinates.map(coord => 
        transform(coord, projection.getCode(), 'EPSG:4326')
      );
    }
    
    // 使用OpenLayers提供的球面距离计算（基于Haversine公式）
    // 复制一个新的LineString对象来计算
    const wgs84Line = new LineString(transformedCoordinates);
    const length = getLength(wgs84Line, { projection: 'EPSG:4326' });
    
    let output;
    
    if (length > 100) {
      output = `${Math.round((length / 1000) * 100) / 100} km`;
    } else {
      output = `${Math.round(length * 100) / 100} m`;
    }
    
    // 添加海里单位
    const nauticalMiles = length / 1852;
    if (nauticalMiles > 0.1) {
      output += ` (${Math.round(nauticalMiles * 100) / 100} 海里)`;
    }
    
    return output;
  }

  /**
   * 格式化面积
   * @param polygon 多边形几何对象
   * @returns 格式化后的面积字符串
   */
  private formatArea(polygon: Polygon): string {
    // 获取坐标
    const coordinates = polygon.getCoordinates();
    
    // 确保是一个有效的多边形
    if (!coordinates || coordinates.length === 0 || coordinates[0].length < 3) {
      return '0 m²';
    }
    
    // 将多边形坐标转换为地理坐标系（EPSG:4326），如果不是的话
    let transformedCoordinates = coordinates;
    const projection = this.map.getView().getProjection();
    
    if (projection.getCode() !== 'EPSG:4326') {
      transformedCoordinates = coordinates.map(ring => 
        ring.map(coord => transform(coord, projection.getCode(), 'EPSG:4326'))
      );
    }
    
    // 使用OpenLayers提供的球面面积计算
    const wgs84Polygon = new Polygon(transformedCoordinates);
    const area = getArea(wgs84Polygon, { projection: 'EPSG:4326' });
    
    let output;
    
    if (area > 10000) {
      output = `${Math.round((area / 1000000) * 100) / 100} km²`;
    } else {
      output = `${Math.round(area * 100) / 100} m²`;
    }
    
    // 添加平方海里单位
    const squareNauticalMiles = area / (1852 * 1852);
    if (squareNauticalMiles > 0.01) {
      output += ` (${Math.round(squareNauticalMiles * 100) / 100} 平方海里)`;
    }
    
    return output;
  }
}

// 样式定义，需要在项目中引入
export const measureStyles = `
.ol-tooltip {
  position: relative;
  background: rgba(0, 0, 0, 0.7);
  border-radius: 4px;
  color: white;
  padding: 4px 8px;
  white-space: nowrap;
  font-size: 12px;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  pointer-events: none;
  z-index: 1000;
}

.ol-tooltip-measure {
  opacity: 1;
  font-weight: bold;
  background-color: rgba(255, 204, 51, 0.9); /* 匹配绘制图形的黄色 #ffcc33 */
  color: white;
  border: 1px solid white;
}

.ol-tooltip-static {
  background-color: rgba(255, 204, 51, 0.7); /* 匹配绘制图形的黄色 #ffcc33 */
  color: white;
  border: 1px solid white;
  padding: 6px 10px;
  font-weight: bold;
}

.ol-tooltip-measure:before,
.ol-tooltip-static:before {
  border-top: 6px solid rgba(255, 204, 51, 0.9); /* 匹配绘制图形的黄色 #ffcc33 */
  border-right: 6px solid transparent;
  border-left: 6px solid transparent;
  content: "";
  position: absolute;
  bottom: -6px;
  margin-left: -7px;
  left: 50%;
}

.ol-tooltip-static:before {
  border-top-color: rgba(255, 204, 51, 0.7); /* 匹配绘制图形的黄色 #ffcc33 */
}

.hidden {
  display: none;
}
`;

/**
 * 创建并添加测量样式到文档
 */
export function addMeasureStyles(): void {
  if (!document.getElementById('measure-styles')) {
    const style = document.createElement('style');
    style.id = 'measure-styles';
    style.innerHTML = measureStyles;
    document.head.appendChild(style);
  }
} 